package db.newversion;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Observable;

import javax.swing.JOptionPane;

import com.sun.org.apache.xpath.internal.functions.WrongNumberArgsException;

import core.Constants;

public class PermissionDB extends Observable implements IDataBase < Combination, Boolean > {
	private static PermissionDB instance = null;
	private HashMap < Combination, Boolean > buffer;

	public static PermissionDB getInstance() {
		if (instance == null) {
			instance = new PermissionDB();
		}
		return instance;
	}

	private PermissionDB() {
		try {
			this.createTable();
		} catch (SQLException e1) {

		}
		try {
			this.importAllPermissions();
		} catch (SQLException e) {
			JOptionPane.showMessageDialog(null, "An error occurred when importing all players from DB", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
		}
	}

	/**
	 * @param toInsert
	 *            the permission
	 * @param objects
	 *            [0] the bow cathegory [1] the age class [3] the gender
	 */
	@Override
	public boolean insert(Boolean toInsert, Object... objects) throws SQLException {
		Combination combination = new Combination(objects [0].toString(), objects [1].toString(), objects [2].toString());
		if (this.buffer.containsKey(combination)) {
			this.update(toInsert, objects);
		} else {
			PreparedStatement psInsert = GeneralDB.getInstance().getConnection().prepareStatement("insert into " + Constants.FINALS_PERMISSIONS_TABLENAME + " values (?, ?, ?, ?)");

			psInsert.setString(1, combination.getBowCathegory());
			psInsert.setString(2, combination.getAgeClass());
			psInsert.setString(3, combination.getGender());
			psInsert.setString(4, toInsert.toString());

			psInsert.executeUpdate();

			this.buffer.put(combination, toInsert);

			this.setChanged();
			this.notifyObservers();
		}
		return true;
	}

	@Override
	public boolean update(Boolean toUpdate, Object... objects) throws SQLException {
		Combination combination = new Combination(objects [0].toString(), objects [1].toString(), objects [2].toString());

		if (this.buffer.get(combination).equals(toUpdate)) {
			return false;
		} else {
			PreparedStatement psUpdate = GeneralDB.getInstance().getConnection()
					.prepareStatement("update " + Constants.FINALS_PERMISSIONS_TABLENAME + " set permission=? WHERE bowCathegory=? AND ageClass=? AND gender=?");

			psUpdate.setString(1, toUpdate.toString());
			psUpdate.setString(2, combination.getBowCathegory());
			psUpdate.setString(3, combination.getAgeClass());
			psUpdate.setString(4, combination.getGender());
			psUpdate.executeUpdate();

			this.buffer.put(combination, toUpdate);

			this.setChanged();
			this.notifyObservers(toUpdate);

			return true;
		}
	}

	@Override
	public boolean delete(Boolean toDelete, Object... objects) throws SQLException {
		Combination combination = new Combination(objects [0].toString(), objects [1].toString(), objects [2].toString());

		PreparedStatement psDelete = GeneralDB.getInstance().getConnection()
				.prepareStatement("delete from " + Constants.FINALS_PERMISSIONS_TABLENAME + " where bowCathegory=? AND ageClass=? AND gender=?");

		psDelete.setString(1, combination.getBowCathegory());
		psDelete.setString(2, combination.getAgeClass());
		psDelete.setString(3, combination.getGender());
		psDelete.executeUpdate();

		this.buffer.remove(combination);

		this.setChanged();
		this.notifyObservers();

		return true;
	}

	@Override
	public HashMap < Combination, Boolean > getAll() {
		HashMap < Combination, Boolean > toReturn = new HashMap < Combination, Boolean >();
		Iterator < Combination > iterator = this.buffer.keySet().iterator();
		while (iterator.hasNext()) {
			Combination tmp = iterator.next();
			toReturn.put(tmp, this.buffer.get(tmp));
		}
		return toReturn;
	}

	@Override
	public Boolean getElement(Object... key) throws WrongNumberArgsException {
		Combination combination = new Combination(key [0].toString(), key [1].toString(), key [2].toString());
		if (this.buffer.containsKey(combination)) {
			return this.buffer.get(combination);
		} else {
			return false;
		}
	}

	/**
	 * Creates the finalsPermissions SQL-Table of the form [bowCathegory,
	 * ageClass, gender, permission]
	 */
	@Override
	public void createTable() throws SQLException {
		Statement statement = GeneralDB.getInstance().getConnection().createStatement();
		statement.execute("create table " + Constants.FINALS_PERMISSIONS_TABLENAME + "(bowCathegory varchar(40), ageClass varchar(40), gender varchar(40), permission varchar(40))");
	}

	/**
	 * drops the table from the DB
	 */
	@Override
	public void dropTable() throws SQLException {
		Statement statement = GeneralDB.getInstance().getConnection().createStatement();
		statement.execute("drop table " + Constants.FINALS_PERMISSIONS_TABLENAME);
		instance = null;
	}

	private void importAllPermissions() throws SQLException {
		this.buffer = new HashMap < Combination, Boolean >();
		ResultSet resultSet = GeneralDB.getInstance().getConnection().createStatement().executeQuery("SELECT * FROM " + Constants.FINALS_PERMISSIONS_TABLENAME);
		while (resultSet.next()) {
			String bowCathegory = resultSet.getString(1);
			String ageClass = resultSet.getString(2);
			String gender = resultSet.getString(3);
			Boolean hasPermission = new Boolean(resultSet.getString(4));
			this.buffer.put(new Combination(bowCathegory, ageClass, gender), hasPermission);
		}
	}
}
